package org.apache.lucene.ocean.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;

/**
 * adds writeVInt, writeVLong, readVInt, readVLong, getInputStream(long
 * position, int length) to RandomAccessFile 
 * 
 */
public class OceanRandomAccessFile extends RandomAccessFile {
  private String mode;
  private boolean isClosed = false;

  public OceanRandomAccessFile(File file, String mode) throws IOException {
    super(file, mode);
    this.mode = mode;
  }

  public void close() throws IOException {
    super.close();
    isClosed = true;
  }

  public static class FileOutputStream extends OutputStream {
    OceanRandomAccessFile randomAccessFile;

    public FileOutputStream(OceanRandomAccessFile randomAccessFile) {
      this.randomAccessFile = randomAccessFile;
    }

    public void write(byte[] b, int off, int len) throws IOException {
      randomAccessFile.write(b, off, len);
    }

    public void write(int b) throws IOException {
      randomAccessFile.write(b);
    }
  }

  public static class FileInputStream extends InputStream {
    OceanRandomAccessFile randomAccessFile;

    public FileInputStream(OceanRandomAccessFile randomAccessFile) {
      this.randomAccessFile = randomAccessFile;
    }

    public int read(byte[] b, int off, int len) throws IOException {
      return randomAccessFile.read(b, off, len);
    }

    public int read() throws IOException {
      return randomAccessFile.read();
    }
  }

  public OutputStream getOutputStream(long position) throws IOException {
    seek(position);
    return new FileOutputStream(this);
  }

  public InputStream getInputStream(long position) throws IOException {
    seek(position);
    return new FileInputStream(this);
  }

  public InputStream getInputStream(long position, int length) throws IOException {
    seek(position);
    return new LimitedFileInputStream(this, length);
  }

  public long readVLong() throws IOException {
    byte b = readByte();
    long i = b & 0x7F;
    for (int shift = 7; (b & 0x80) != 0; shift += 7) {
      b = readByte();
      i |= (b & 0x7FL) << shift;
    }
    return i;
  }

  public int readVInt() throws IOException {
    byte b = readByte();
    int i = b & 0x7F;
    for (int shift = 7; (b & 0x80) != 0; shift += 7) {
      b = readByte();
      i |= (b & 0x7F) << shift;
    }
    return i;
  }

  public void writeVLong(long i) throws IOException {
    while ((i & ~0x7F) != 0) {
      writeByte((byte) ((i & 0x7f) | 0x80));
      i >>>= 7;
    }
    writeByte((byte) i);
  }

  public void writeVInt(int i) throws IOException {
    while ((i & ~0x7F) != 0) {
      writeByte((byte) ((i & 0x7f) | 0x80));
      i >>>= 7;
    }
    writeByte((byte) i);
  }
}
